/*
 * Copyright (C) 2010, Funcom AS, All Rights Reserved
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 *  @authors
 *  Svein Gunnar Larsen <sveingunnarlarsen@gmail.com>
 *  Erik Thune Lund <culex.eriklund@gmail.com>
 *  Michel Krohn-Dale <kronicz@gmail.com>
 */

package com.funcom.peeler;

import com.funcom.peeler.action.Change;

import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Queue;

public class History {

    private WorkBench workbench;

    private Queue<Change> pending_changes = new LinkedList<Change>();
    private List<Change> history = new LinkedList< Change >();
    private ListIterator<Change> change_iter = history.listIterator();
    private ListIterator<Change> save_mark;

    public History( WorkBench workbench ) {
        if ( workbench == null ) throw new NullPointerException();
        this.workbench = workbench;
    }

    public synchronized void pushChange( final Change change) {

        workbench.getBui().execute( new WorkBench.Task() {

            public void run() {

                if ( change == null ) return;

                pending_changes.add( change);
            }
        });
    }

    public synchronized void doPendingChanges() {

        Change change = pending_changes.poll();

        while ( change != null ) {

            //Discard future history when changing the past
            if ( change_iter.hasNext() ) {
                history = history.subList( 0, change_iter.nextIndex() );

                // Update the save mark so that it's located in the new history list
                if ( save_mark != null ) {

                    if ( ( save_mark.previousIndex() + 1 ) > history.size() )
                        save_mark = history.listIterator( 0 );
                    else
                        save_mark = history.listIterator( save_mark.previousIndex() + 1 );
                }
            }

            // Add some history and move the iterator
            history.add( change );
            change_iter = history.listIterator( history.size() );

            // For next loop iteration
            change = pending_changes.poll();
        }
    }

    public synchronized void undo() {

        workbench.getBui().execute( new WorkBench.Task() {

            public void run() {

                if ( change_iter == null ) {
                    change_iter = history.listIterator( history.size() );
                }

                // Undo the last change and move the iterator
                if ( change_iter.hasPrevious() )
                    change_iter.previous().undoChange();

                return;
            }
        });
    }

    public synchronized void redo() {

        workbench.getBui().execute( new WorkBench.Task() {

            public void run() {

                if ( change_iter == null ) {
                    change_iter = history.listIterator( history.size() );
                }

                // Redo the last change and move the iterator
                if ( change_iter.hasNext() )
                    change_iter.next().doChange();

                return;
            }
        });
    }

    public boolean hasPrevious() {
        return change_iter.hasPrevious();
    }

    public synchronized void mark() {
        save_mark = history.listIterator( change_iter.previousIndex() + 1 );
    }

    public boolean needSave() {

        return true;
        /*// The history is empty, no save needed, return false
        if ( history.isEmpty() ) return false;

        // If never saved and the history has some changes, do save, return true
        if ( save_mark == null ) return true;

        // Otherwise, compare indices of iterators, return result
        return save_mark.previousIndex() != change_iter.previousIndex();*/
    }
}
